package com.sina.finance.api.framework.permission.realm;

import com.sina.finance.api.framework.constants.SpringBeanConstants;
import com.sina.finance.api.framework.permission.CvsPermission;
import com.sina.finance.api.framework.permission.exception.NoSecretException;
import com.sina.finance.api.framework.permission.exception.SignCheckException;
import com.sina.finance.api.framework.service.AppKeyAndSecretService;
import com.sina.finance.api.framework.service.BizIdAndAppKeyService;
import com.sina.finance.api.framework.service.ISecurityService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.io.IOException;


public class StatelessRealm extends AuthorizingRealm {

    @Resource(name= SpringBeanConstants.SECURITY_SERVICE)
    private ISecurityService securityService;

    @Resource
    private AppKeyAndSecretService appKeyAndSecretService;

    @Resource
    private BizIdAndAppKeyService bizIdAndAppKeyService;

    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持StatelessToken类型的Token
        return token instanceof StatelessToken;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //根据用户名查找角色，请根据需求实现
        String appKey = (String) principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo =  new SimpleAuthorizationInfo();
        authorizationInfo.addObjectPermission(new CvsPermission(appKeyAndSecretService.findAllPermissions(appKey)));
        return authorizationInfo;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        StatelessToken statelessToken = (StatelessToken) token;

        String appKey = statelessToken.getAppKey();

        String partnerCode = statelessToken.getPartnerCode();

        if (!bizIdAndAppKeyService.isBizIdAndKeyBelongSamePerson(partnerCode, appKey)) {
            throw new AuthenticationException("业务标识与app_key不属于同一个用户");
        }

        checkAppkeyExists(appKey);

        String appSecret = getSecret(appKey);//根据Key获取密钥

        if (appSecret == null) {
            throw new NoSecretException("状态异常, 找不到key对应的secret");
        }

        String clientDigest = statelessToken.getClientDigest();

        try {
            if(!securityService.checkSign(statelessToken.getParams(), clientDigest, appSecret)){
                throw new SignCheckException("签名校验失败");
            }
        } catch (IOException e) {
            throw new SignCheckException("签名校验失败");
        }

        return new SimpleAuthenticationInfo(
                appKey,
                clientDigest,
                getName());
    }

    private void checkAppkeyExists(String appKey) {
        if(!appKeyAndSecretService.isAppKeyExist(appKey)) {
            throw new UnknownAccountException("不存在的app_key");
        }
    }

    private String getSecret(String appKey) {
        return appKeyAndSecretService.getSecret(appKey);
    }
}
